feat(prisma-next)!: make the adapter EQL v3 only (fixes Supabase superuser block, #709)#712
Conversation
Remove the EQL v2 surface from `@cipherstash/prisma-next` entirely — the install path, the authoring constructors, the runtime codecs, and the v2 subpath exports — so the adapter installs only EQL v3 and works on managed Postgres (e.g. Supabase) as a non-superuser. Install path (the root cause of the Supabase block): - Re-root the v3 baseline migration as an invariant-only genesis edge (`from: null`); the contract now models no storage; the head ref requires only `cipherstash:install-eql-v3-bundle-v1`. The v2 and v3 baselines were chained (v3 started from v2's `to` state, head required both invariants), so `migration apply` always ran the v2 install first — which fails on a non-superuser role. Re-emit the contract-space artefacts. - Delete the v2 baseline migration (`20260601T0000_install_eql_bundle`). API/code removal: - Delete the v2 authoring/runtime/codec code: `cipherstashFromStackV2`, the `*V2` constructors, the v2 codec runtime + composite wire, the baked `eql-install.generated`, and the v2 codec-control hooks. - Remove the `./middleware` and `./migration` subpath exports. - Move the version-neutral `stampRoutingKeysFromAst` into `execution/routing` so `src/middleware/` can be removed; keep the shared value envelopes (`EncryptedString`/`BigInt`/`Boolean`/`Date`/`Json`) and `decryptAll`. The v3 surface is unchanged. Prune the v2 tests and update the shared/v3 tests (descriptor, migration, bundling-isolation, operator/type gating) for the v3-only reality. Refs #709
…3-only Rewrite `DEVELOPING.md` for the v3 architecture (catalog-derived domains, the `eql*` operator surface, the query-term seam, the genesis-edge migration) and match this repo's actual `src/` layout. Drop the removed v2 surface from the README subpath table, the bundled `stash-prisma-next` skill, the `AGENTS.md` repository layout, and the prisma example JSDoc. Refs #709
🦋 Changeset detectedLatest commit: 9314afb The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
📝 WalkthroughWalkthrough
ChangesPrisma Next EQL v3-only transition
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related issues
Possibly related PRs
Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant PrismaNext
participant CodecRuntime
participant BulkEncryptMiddlewareV3
participant CipherstashSdk
PrismaNext->>CodecRuntime: encode encrypted envelope
CodecRuntime->>BulkEncryptMiddlewareV3: validate middleware registration
BulkEncryptMiddlewareV3->>BulkEncryptMiddlewareV3: stamp table and column routing keys
BulkEncryptMiddlewareV3->>CipherstashSdk: bulkEncrypt plaintext targets
CipherstashSdk-->>BulkEncryptMiddlewareV3: return ciphertext
BulkEncryptMiddlewareV3-->>PrismaNext: rewrite parameter to v3 wire format
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
freshtonic
left a comment
There was a problem hiding this comment.
Overview
Makes @cipherstash/prisma-next EQL v3 only — removing the v2 install path, authoring constructors, runtime codecs, and the ./middleware / ./migration subpath exports (~20k lines deleted across 45 files). The behavioural fix for the rc.3 F3 Supabase blocker: the v2 and v3 baselines were chained, so a fresh DB ran the v2 install first, and the v2 bundle needs a Postgres superuser — unusable on Supabase even for a pure-v3 app. The v3 baseline is re-rooted as an invariant-only genesis edge and the head ref now requires only the v3 bundle.
This is a large but overwhelmingly subtractive change, and it's internally consistent. Approving.
What I verified
Migration graph re-rooting (the actual fix) — coherent. Traced the content-addressed graph on the branch:
refs/head.jsonnow requires exactly one invariant,cipherstash:install-eql-v3-bundle-v1(the v2install-eql-bundle-v1invariant is gone), at hashefd408…431d51e.- The old v2 edge
20260601T0000_install_eql_bundle/is fully deleted (all five artefacts), not left dangling. - The v3 edge
20260601T0100_install_eql_v3_bundle/migration.jsonis re-rootedfrom: null → to: efd408…431d51e(was a self-loop off the v2 baseline hash);migration.ts describe()matches. - Exactly one path reaches head:
genesis (from: null) → install-eql-v3-bundle → head, installing only v3. No orphaned edges. contract.prisma/contract.jsonmodel no storage (EqlV2Configuration/eql_v2_configurationremoved as a model; only narrative prose mentions it). All four content hashes agree end-to-end (head.jsonhash= v3migration.jsonto= v3end-contract.jsonstorageHash=src/contract.jsonstorageHash=efd408…431d51e), so the modelled contract matches the edge's end state and head is reachable.
Control plane / exports — coherent. control.ts drops the v2 baseline migration and the six v2 codec-control hooks from the contract space, leaving only the v3 genesis edge and cipherstashV3CodecControlHooks (identity expandNativeType, no onFieldEvent — so v3 columns emit no add_search_config/remove_search_config, correct for domain-typed columns). package.json and tsup.config.ts drop ./middleware and ./migration in lockstep; exports/stack.ts and exports/runtime.ts are reduced cleanly to the v3 surface; exports/migration.ts and exports/middleware.ts are deleted. The shared stampRoutingKeysFromAst is moved into execution/routing.ts with proper value imports (EncryptedEnvelopeBase, setHandleRoutingKey) so src/middleware/ could be deleted.
Changesets — correct. @cipherstash/prisma-next minor + stash patch (for the bundled skill). The repo is in changesets prerelease mode (.changeset/pre.json, tag rc), and prisma-next is 1.0.0-rc.3, so minor for a pre-GA breaking change is consistent with the whole EQL-v3 rc train — major would wrongly imply 2.0.0. The ! breaking marker in the title + the detailed breaking-change changeset body cover the migration guidance.
Meta files & docs — updated in-PR (as the repo requires): AGENTS.md repository layout now reads "EQL v3 only", the prisma example JSDoc drops the stale v2 note, README/DEVELOPING/skill rewritten for v3.
No dangling references — verified across the whole branch. For every removed symbol (cipherstashFromStackV2, deriveStackSchemas, createCipherstashSdk, createCipherstashRuntimeDescriptor, the v2 cipherstash* operators, the encrypted*V2/Encrypted*V2 factories, EncryptedDouble) and every removed subpath (./middleware, ./migration), there are zero surviving imports or usages in packages/** (including cross-package), examples/, or e2e/ — the names now appear only in doc comments and CHANGELOG history. The ./middleware//migration hits that remain are upstream Prisma-Next framework subpaths (@prisma-next/postgres/migration, etc.), not the removed local ones. Every package.json export and tsup entry resolves to an existing source file. (Note: @cipherstash/prisma-next was already ESM-only at the merge base — no require/CJS entries to preserve — so the repo's "don't drop CJS" rule doesn't apply here.)
Notes — non-blocking
-
Acknowledged dead code:
isBulkEncryptMiddlewareRegisteredinexecution/middleware-registry.tsis now marked-but-never-read — v3'sencodenever wired the "middleware not registered" diagnostic that consulted it (that guard lived in the deleted v2 codec). The PR documents this honestly and defers it. Fine to leave, but the registry + its populate path is now dead weight; a follow-up should either wire a v3 diagnostic or delete the registry. -
Two stale doc comments name removed symbols (comment-accuracy only, nothing compiles against them):
src/v3/runtime-v3.ts:4still referencescreateCipherstashRuntimeDescriptor(the live export iscreateCipherstashV3RuntimeDescriptor), andtest/v3/from-stack-v3.test.ts:9describes the v2cipherstashFromStackV2as "a separate, untouched" surface when v2 was in fact deleted. Trivial to fix in passing. -
Single squashed code commit. The install-path change and the ~20k-line v2 removal share
control.ts, so they're in one commit rather than split. The author explains patch-level staging wasn't available and splitting risked a non-building intermediate. Reasonable given the tooling constraint; noting only.
Verdict
Approve. The behavioural fix is exactly right — re-rooting to a v3-only genesis edge removes the v2 install (and its superuser requirement) from the apply path, and the content-addressed graph, contract artefacts, and head ref are all hash-consistent. The API/subpath removal is complete and leaves no dangling references anywhere in the tree, examples, or e2e. Meta files, docs, and changesets are updated per repo policy. The three notes are all non-blocking follow-ups (dead registry, two stale comments, commit granularity).
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/prisma-next/README.md (1)
81-81: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse
eqlMatchin this example.cipherstashIlikeis legacy v2 syntax; this v3 README should show the free-text search operator used elsewhere here (eqlMatch).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/prisma-next/README.md` at line 81, Update the README query example to replace the legacy cipherstashIlike operator with eqlMatch, matching the v3 free-text search syntax used elsewhere in the document.Source: Coding guidelines
🧹 Nitpick comments (1)
packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/migration.ts (1)
55-66: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRationale is accurate; align the neighbouring "self-edge" wording.
The
data-class justification here now describes a genesis edge (from: null→ empty-storage hash), but the adjacent comment at Line 74–75 still says "this is an invariant-only self-edge." Since you retired the "self-edge" framing in this block, update that trailing comment too so the file's genesis-vs-self classification is consistent.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/migration.ts` around lines 55 - 66, Update the adjacent trailing comment near operationClass in the migration definition to remove the outdated “self-edge” wording and describe the edge consistently as a genesis/no-storage-movement edge, preserving its invariant-only meaning.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/prisma-next/README.md`:
- Line 13: Remove the outdated “legacy v2 surface keeps its cipherstash* names”
clause from the type-safe query operators bullet in the README, leaving only the
current EQL v3 operator vocabulary. Ensure nearby README references consistently
omit the removed EQL v2 surface and reflect the current package exports.
---
Outside diff comments:
In `@packages/prisma-next/README.md`:
- Line 81: Update the README query example to replace the legacy
cipherstashIlike operator with eqlMatch, matching the v3 free-text search syntax
used elsewhere in the document.
---
Nitpick comments:
In
`@packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/migration.ts`:
- Around line 55-66: Update the adjacent trailing comment near operationClass in
the migration definition to remove the outdated “self-edge” wording and describe
the edge consistently as a genesis/no-storage-movement edge, preserving its
invariant-only meaning.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5d4d7fb6-11e1-41c8-8ac3-04d1287b3492
⛔ Files ignored due to path filters (1)
packages/prisma-next/src/migration/eql-install.generated.tsis excluded by!**/*.generated.*
📒 Files selected for processing (94)
.changeset/prisma-next-v3-only-install.md.changeset/stash-prisma-next-skill-v3-only.mdAGENTS.mdexamples/prisma/src/db.tspackages/prisma-next/DEVELOPING.mdpackages/prisma-next/README.mdpackages/prisma-next/migrations/20260601T0000_install_eql_bundle/end-contract.d.tspackages/prisma-next/migrations/20260601T0000_install_eql_bundle/end-contract.jsonpackages/prisma-next/migrations/20260601T0000_install_eql_bundle/migration.jsonpackages/prisma-next/migrations/20260601T0000_install_eql_bundle/migration.tspackages/prisma-next/migrations/20260601T0000_install_eql_bundle/ops.jsonpackages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/end-contract.d.tspackages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/end-contract.jsonpackages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/migration.jsonpackages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/migration.tspackages/prisma-next/migrations/refs/head.jsonpackages/prisma-next/package.jsonpackages/prisma-next/src/contract-authoring.tspackages/prisma-next/src/contract.d.tspackages/prisma-next/src/contract.jsonpackages/prisma-next/src/contract.prismapackages/prisma-next/src/execution/cell-codec-factory.tspackages/prisma-next/src/execution/codec-runtime.tspackages/prisma-next/src/execution/envelope-base.tspackages/prisma-next/src/execution/envelope-double.tspackages/prisma-next/src/execution/helpers.tspackages/prisma-next/src/execution/middleware-registry.tspackages/prisma-next/src/execution/operators.tspackages/prisma-next/src/execution/parameterized.tspackages/prisma-next/src/execution/routing.tspackages/prisma-next/src/exports/column-types.tspackages/prisma-next/src/exports/control.tspackages/prisma-next/src/exports/middleware.tspackages/prisma-next/src/exports/migration.tspackages/prisma-next/src/exports/runtime.tspackages/prisma-next/src/exports/stack.tspackages/prisma-next/src/extension-metadata/codec-metadata.tspackages/prisma-next/src/extension-metadata/constants.tspackages/prisma-next/src/extension-metadata/descriptor-meta.tspackages/prisma-next/src/middleware/bulk-encrypt.tspackages/prisma-next/src/migration/call-classes.tspackages/prisma-next/src/migration/cipherstash-codec.tspackages/prisma-next/src/migration/codec-hooks-factory.tspackages/prisma-next/src/migration/eql-bundle.tspackages/prisma-next/src/stack/derive-schemas.tspackages/prisma-next/src/stack/from-stack-v3.tspackages/prisma-next/src/stack/from-stack.tspackages/prisma-next/src/stack/sdk-adapter.tspackages/prisma-next/src/types/codec-types.tspackages/prisma-next/src/types/operation-types.tspackages/prisma-next/src/v3/bulk-encrypt-v3.tspackages/prisma-next/src/v3/envelope-number.tspackages/prisma-next/test/abort.test.tspackages/prisma-next/test/authoring.test.tspackages/prisma-next/test/bulk-encrypt-middleware.helpers.tspackages/prisma-next/test/bulk-encrypt-middleware.test.tspackages/prisma-next/test/bundling-isolation.test.tspackages/prisma-next/test/call-classes.test.tspackages/prisma-next/test/call-classes.types.test-d.tspackages/prisma-next/test/cipherstash-codec-numeric.test.tspackages/prisma-next/test/cipherstash-codec-other-codecs.test.tspackages/prisma-next/test/cipherstash-codec-string.test.tspackages/prisma-next/test/cipherstash-codec.test.tspackages/prisma-next/test/codec-runtime.test.tspackages/prisma-next/test/column-types.test.tspackages/prisma-next/test/decrypt-all.test.tspackages/prisma-next/test/derive-schemas.test.tspackages/prisma-next/test/descriptor.test.tspackages/prisma-next/test/envelope-double.test.tspackages/prisma-next/test/equality-trait-removal.test.tspackages/prisma-next/test/from-stack-divergence.test.tspackages/prisma-next/test/helpers.test.tspackages/prisma-next/test/helpers.types.test-d.tspackages/prisma-next/test/live/side-by-side-clients-live-pg.test.tspackages/prisma-next/test/operation-types.types.test-d.tspackages/prisma-next/test/operator-lowering-equality.test.tspackages/prisma-next/test/operator-lowering-order-range.test.tspackages/prisma-next/test/operator-lowering-text-search.test.tspackages/prisma-next/test/operator-lowering.helpers.tspackages/prisma-next/test/operator-lowering.test.tspackages/prisma-next/test/psl-interpretation-numeric.test.tspackages/prisma-next/test/psl-interpretation-other-types.test.tspackages/prisma-next/test/psl-interpretation.test.tspackages/prisma-next/test/runtime-descriptor.test.tspackages/prisma-next/test/sdk-adapter.test.tspackages/prisma-next/test/v3/bulk-encrypt-v3.test.tspackages/prisma-next/test/v3/constants-v3.test.tspackages/prisma-next/test/v3/envelope-number.test.tspackages/prisma-next/test/v3/migration-v3.test.tspackages/prisma-next/test/v3/operator-gating-v3.test.tspackages/prisma-next/test/v3/properties.test.tspackages/prisma-next/test/v3/runtime-v3.test.tspackages/prisma-next/tsup.config.tsskills/stash-prisma-next/SKILL.md
💤 Files with no reviewable changes (48)
- packages/prisma-next/migrations/20260601T0000_install_eql_bundle/migration.json
- packages/prisma-next/test/from-stack-divergence.test.ts
- packages/prisma-next/test/cipherstash-codec-numeric.test.ts
- packages/prisma-next/test/helpers.test.ts
- packages/prisma-next/src/migration/eql-bundle.ts
- packages/prisma-next/test/operator-lowering-order-range.test.ts
- packages/prisma-next/test/cipherstash-codec.test.ts
- packages/prisma-next/migrations/20260601T0000_install_eql_bundle/migration.ts
- packages/prisma-next/src/exports/middleware.ts
- packages/prisma-next/src/execution/envelope-double.ts
- packages/prisma-next/src/exports/migration.ts
- packages/prisma-next/test/call-classes.types.test-d.ts
- packages/prisma-next/test/sdk-adapter.test.ts
- packages/prisma-next/test/derive-schemas.test.ts
- packages/prisma-next/test/operator-lowering-text-search.test.ts
- packages/prisma-next/test/operator-lowering-equality.test.ts
- packages/prisma-next/migrations/20260601T0000_install_eql_bundle/end-contract.json
- examples/prisma/src/db.ts
- packages/prisma-next/src/execution/codec-runtime.ts
- packages/prisma-next/test/bulk-encrypt-middleware.test.ts
- packages/prisma-next/test/runtime-descriptor.test.ts
- packages/prisma-next/test/psl-interpretation-other-types.test.ts
- packages/prisma-next/src/migration/call-classes.ts
- packages/prisma-next/test/envelope-double.test.ts
- packages/prisma-next/test/operator-lowering.test.ts
- packages/prisma-next/src/stack/sdk-adapter.ts
- packages/prisma-next/test/psl-interpretation-numeric.test.ts
- packages/prisma-next/src/stack/from-stack.ts
- packages/prisma-next/migrations/20260601T0000_install_eql_bundle/end-contract.d.ts
- packages/prisma-next/test/operator-lowering.helpers.ts
- packages/prisma-next/test/helpers.types.test-d.ts
- packages/prisma-next/test/codec-runtime.test.ts
- packages/prisma-next/src/execution/parameterized.ts
- packages/prisma-next/tsup.config.ts
- packages/prisma-next/src/execution/cell-codec-factory.ts
- packages/prisma-next/src/execution/helpers.ts
- packages/prisma-next/test/cipherstash-codec-string.test.ts
- packages/prisma-next/test/live/side-by-side-clients-live-pg.test.ts
- packages/prisma-next/src/middleware/bulk-encrypt.ts
- packages/prisma-next/src/execution/operators.ts
- packages/prisma-next/test/cipherstash-codec-other-codecs.test.ts
- packages/prisma-next/test/call-classes.test.ts
- packages/prisma-next/src/migration/codec-hooks-factory.ts
- packages/prisma-next/test/v3/constants-v3.test.ts
- packages/prisma-next/src/migration/cipherstash-codec.ts
- packages/prisma-next/test/column-types.test.ts
- packages/prisma-next/src/stack/derive-schemas.ts
- packages/prisma-next/src/exports/column-types.ts
… stale docs James's review (#712) and CodeRabbit. Wire the "middleware not wired" diagnostic on the v3 write path. `isBulkEncryptMiddlewareRegistered` was marked-but-never-read: the read site lived in the v2 `cell-codec-factory.ts`, deleted in this PR, and v3 never had one. Port it to `CipherstashV3CellCodec#encode` so an SDK with no `bulkEncryptMiddlewareV3(sdk)` registered fails fast with `RUNTIME.ENCODE_FAILED` and a copy-pasteable wiring snippet instead of an opaque pg serialise error. Memoised per codec (the registry is add-only), so it costs one WeakSet lookup rather than one per cell. Docs and comments naming removed symbols: - README: drop the "legacy v2 surface keeps its `cipherstash*` names" clause, and switch the query example from `cipherstashIlike` to `eqlMatch`. The LIKE wildcard goes too — `eqlMatch` is bloom token containment (`eql_v3.contains`), not SQL `LIKE`, so `"%@example.com"` would have been misleading. - migration.ts: the trailing rationale still said "invariant-only self-edge" after the edge was re-rooted as genesis. - runtime-v3.ts: referenced the removed `createCipherstashRuntimeDescriptor`, and described a v2/v3 co-registration constraint that no longer exists. - operator-gating-v3.test.ts: header claimed to pin v2/v3 method-name disjointness; the body now pins the `eql*` prefix instead. - from-stack-v3.test.ts: described `cipherstashFromStackV2` as "separate, untouched" when it was removed outright. - DEVELOPING.md: said the v3 codec raises no wiring diagnostic — now it does. 320 -> 322 unit tests (both new cases cover the diagnostic: it fires for an unregistered SDK, and stays silent for an already-encrypted envelope). Typecheck, build, and biome clean.
|
Thanks both — all review points addressed in 9314afb.
CI: the Validation: 322/322 unit tests, typecheck clean, build clean, 0 biome errors. |
|
Tip For best results, initiate chat on the files or code changes.
🐇✅ ✏️ Learnings added
If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! |
…731) * ci(integration): isolate live-DB stacks instead of serialising them Integration jobs were being CANCELLED, not run — four times in ~80 minutes on 2026-07-20, most recently the `db=supabase` leg of #712, which is the exact variant that PR exists to fix. Cause: the three integration workflows share one job-level concurrency group, `integration-live-db-<db>`, deliberately not scoped by ref (d02bf63) because two PRs contend for a fixed host port as much as two pushes to one PR. But GitHub Actions allows only ONE in-progress plus ONE pending run per group — a third contender is cancelled outright. With three workflows funnelling into two keys, that fires under any load. The failure mode is worse than a flake: a cancelled job never runs, so its check goes ABSENT rather than red. The signal is silently lost, and `main` is not branch-protected, so nothing blocks the merge. Remove the contention rather than serialising it. A new `integration-db` composite action gives every job: - its own compose project name (run id + attempt + job + variant), so container names cannot collide; and - EPHEMERAL host ports — `CS_PG_PORTS` / `CS_PGRST_PORTS` carry a bare container port, so compose publishes with no fixed host side and the assigned port is read back with `docker compose port`. Nothing is shared between jobs, so nothing needs to queue, and the concurrency groups are gone from all three workflows. The compose files keep their fixed 55432 / 55433 / 55430 mappings when the vars are unset, so local dev and the help text in `test-kit/src/env.ts` are unchanged. Dropped the pre-`up` `docker compose down` too. With unique project names it is a no-op, and blanket-pruning is now actively unsafe: without the concurrency group, another job's stack may be live on the same runner. Also, since this adds a composite action: `.github/actions/` had no CODEOWNERS rule, though such actions run arbitrary steps in the same job with the same secrets as the workflow calling them. Added the rule and the matching assertion in `supply-chain.e2e.test.ts` (verified it fails without it). Fixed a stale claim in the Drizzle workflow header that `PGRST_URL` is left unset — the matrix had been setting it. Verified: compose interpolation resolves to the fixed mapping by default and to an ephemeral publish under the CI vars (`docker compose config`); YAML parses; the action's shell body is syntax-clean with no GitHub templating interpolated into it; 18/18 supply-chain e2e tests pass. * fix(ci): validate every port readback, not just Postgres CodeRabbit caught a real asymmetry in the new action: `pg_port` was checked for emptiness but the supabase branch built `pgrest_url` straight from `$(port_of postgrest 3000)`. `docker compose port` exits 0 with EMPTY stdout when a port is not bound, so an unbound PostgREST would have silently yielded `http://localhost:` and handed every `PGRST_URL` consumer (the Drizzle-supabase leg, both Supabase-workflow steps) a malformed URL instead of the immediate error the Postgres path already gave. Move the check into `port_of` itself so it applies by construction and the asymmetry cannot come back, rather than adding a second call-site guard. Each port is now captured in its own bare assignment so `set -e` fails the step unambiguously on a non-zero `port_of`. Verified with a stubbed `docker` that returns a port for `db` and nothing for `postgrest`: the Postgres read succeeds, the guard fires for postgrest, and the script exits 1 before exporting anything.
Makes
@cipherstash/prisma-nextEQL v3 only — the install path, the authoring constructors, the runtime codecs, and the v2 subpath exports are all removed. This fixes the rc.3 skilltester F3 blocker: the adapter was unusable on Supabase becauseprisma-next migration applyinstalled the EQL v2 bundle, whose install requires a Postgres superuser.Closes #709.
Root cause (install path)
The v2 and v3 baselines were chained: the v3 migration edge started from the v2 baseline's
tostate, andrefs/head.jsonrequired both invariants. So on a fresh database the only path to head ran the v2 install first — and the v2 bundle fails on Supabase's non-superuserpostgresrole, even for a pure-v3 app. (#694 only changed how the v3 baseline sources its SQL; it never removed v2 from the apply path.)Fix: the v3 baseline is re-rooted as an invariant-only genesis edge (
from: null), the contract models no storage (theeql_v2_configurationtable is gone), and the head ref requires onlycipherstash:install-eql-v3-bundle-v1. Contract-space artefacts are re-emitted (contract.json,head.json, the v3migration.json).prisma-next migration applynow installs only EQL v3 and works on Supabase as a non-superuser.Breaking — API removed
cipherstashFromStackV2,deriveStackSchemas,createCipherstashSdk(from./stack) → usecipherstashFromStack(v3).encrypted*V2TS factories andcipherstash.Encrypted*V2PSL constructors → use the v3 domain factories/constructors (text/textSearch/bigIntOrd/ … andcipherstash.TextSearch()etc.).createCipherstashRuntimeDescriptor, thecipherstash*operators/helpers, and theEncryptedDoubleenvelope → use the v3 runtime (createCipherstashV3RuntimeDescriptor,bulkEncryptMiddlewareV3, theeql*operators,EncryptedNumber)../middlewareand./migrationremoved.Kept: the version-neutral value envelopes (
EncryptedString/BigInt/Boolean/Date/Json) anddecryptAll— the v3 surface is unchanged. The one shared v2→v3 edge,stampRoutingKeysFromAst, was moved intoexecution/routingsosrc/middleware/could be deleted.Scale
~19,900 lines removed across 45 deleted files (the bulk is the baked v2 install SQL + the v2 codec/authoring/runtime layer). Two changesets:
@cipherstash/prisma-nextminor + astashpatch for the bundledstash-prisma-nextskill.Validation
bundling-isolationgreen against freshdist; 0 biome errors.assertDescriptorSelfConsistencyand the materialise→disk→integrity-read round-trip.Docs
README subpath table, the
stash-prisma-nextskill, theAGENTS.mdrepository layout, and the prisma example JSDoc are updated;DEVELOPING.mdis rewritten for the v3 architecture (catalog-derived domains, theeql*surface, the query-term seam, the genesis-edge migration).One thing to note — now resolved
isBulkEncryptMiddlewareRegisteredinexecution/middleware-registry.tswasmarked-but-never-read: the
RUNTIME.ENCODE_FAILED"middleware not wired" guardlived in the v2
cell-codec-factory.ts(deleted here), and v3 never wired one.Rather than leave the registry as dead weight, the guard is now ported to
CipherstashV3CellCodec#encode— an SDK with nobulkEncryptMiddlewareV3(sdk)registered fails fast with a copy-pasteable wiring snippet instead of an opaque
pg serialise error. Memoised per codec (the registry is add-only), so it costs
one WeakSet lookup, not one per cell. Two new tests cover it;
DEVELOPING.mdand the changeset are updated to match.
Review note
Two commits: the code change, then docs. Not split into "install-path" vs "code-removal" because
control.tscarries both and patch-level staging wasn't available in the automation environment — splitting risked a non-building intermediate commit.Summary by CodeRabbit
EncryptedDoublewithEncryptedNumber.eql*query operators.Summary by CodeRabbit
Breaking Changes
eql*operators.New Features
bulkEncryptMiddlewareV3.Bug Fixes
RUNTIME.ENCODE_FAILEDdiagnostic.Documentation